/*
Java board game library.
Copyright (C) 2011  Deepesh Garg

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

package d.g.boardgames.chess;

import d.g.boardgames.*;
import d.g.boardgames.chess.ChessCellState.PieceColor;
import d.g.boardgames.chess.ChessCellState.PieceType;

public class ChessBoard extends Board<ChessCellState, ChessMove> {
	
	PieceColor turn = PieceColor.WHITE;
	Cell passedPawn = null;
	boolean whiteKingSideCastleAllowed;
	boolean whiteQueenSideCastleAllowed;
	boolean blackKingSideCastleAllowed;
	boolean blackQueenSideCastleAllowed;
	
	AnalysisData analysisData;
	
	public ChessBoard() {
		this(false);
	}
	
	public ChessBoard (boolean blank) {
		super (8, 8);
		if (blank == false) {
			setCellState(0, 0, ChessCellState.BLACK_ROOK);
			setCellState(0, 1, ChessCellState.BLACK_KNIGHT);
			setCellState(0, 2, ChessCellState.BLACK_BISHOP);
			setCellState(0, 3, ChessCellState.BLACK_QUEEN);
			setCellState(0, 4, ChessCellState.BLACK_KING);
			setCellState(0, 5, ChessCellState.BLACK_BISHOP);
			setCellState(0, 6, ChessCellState.BLACK_KNIGHT);
			setCellState(0, 7, ChessCellState.BLACK_ROOK);
			setCellState(1, 0, ChessCellState.BLACK_PAWN);
			setCellState(1, 1, ChessCellState.BLACK_PAWN);
			setCellState(1, 2, ChessCellState.BLACK_PAWN);
			setCellState(1, 3, ChessCellState.BLACK_PAWN);
			setCellState(1, 4, ChessCellState.BLACK_PAWN);
			setCellState(1, 5, ChessCellState.BLACK_PAWN);
			setCellState(1, 6, ChessCellState.BLACK_PAWN);
			setCellState(1, 7, ChessCellState.BLACK_PAWN);

			setCellState(6, 0, ChessCellState.WHITE_PAWN);
			setCellState(6, 1, ChessCellState.WHITE_PAWN);
			setCellState(6, 2, ChessCellState.WHITE_PAWN);
			setCellState(6, 3, ChessCellState.WHITE_PAWN);
			setCellState(6, 4, ChessCellState.WHITE_PAWN);
			setCellState(6, 5, ChessCellState.WHITE_PAWN);
			setCellState(6, 6, ChessCellState.WHITE_PAWN);
			setCellState(6, 7, ChessCellState.WHITE_PAWN);
			setCellState(7, 0, ChessCellState.WHITE_ROOK);
			setCellState(7, 1, ChessCellState.WHITE_KNIGHT);
			setCellState(7, 2, ChessCellState.WHITE_BISHOP);
			setCellState(7, 3, ChessCellState.WHITE_QUEEN);
			setCellState(7, 4, ChessCellState.WHITE_KING);
			setCellState(7, 5, ChessCellState.WHITE_BISHOP);
			setCellState(7, 6, ChessCellState.WHITE_KNIGHT);
			setCellState(7, 7, ChessCellState.WHITE_ROOK);
			
			whiteKingSideCastleAllowed = true;
			whiteQueenSideCastleAllowed = true;
			blackKingSideCastleAllowed = true;
			blackQueenSideCastleAllowed = true;
		}
	}
	
	@Override
	public ChessBoard move (ChessMove chessMove) {
		ChessBoard b = clone();
		b.passedPawn = null;
		//Check for casteling
		if (chessMove.getCasteling() != ChessMove.Casteling.NONE) {
			if (b.getTurn() == PieceColor.WHITE) {
				if (chessMove.getCasteling() == ChessMove.Casteling.KING_SIDE) {
					b.setCellState(7, 4, null);
					b.setCellState(7, 5, ChessCellState.WHITE_ROOK);
					b.setCellState(7, 6, ChessCellState.WHITE_KING);
					b.setCellState(7, 7, null);
				} else if (chessMove.getCasteling() == ChessMove.Casteling.QUEEN_SIDE) {
					b.setCellState(7, 0, null);
					b.setCellState(7, 2, ChessCellState.WHITE_KING);
					b.setCellState(7, 3, ChessCellState.WHITE_ROOK);
					b.setCellState(7, 4, null);
				}
				b.setWhiteKingSideCastleAllowed(false);
				b.setWhiteQueenSideCastleAllowed(false);
			} else if (b.getTurn() == PieceColor.BLACK) {
				if (chessMove.getCasteling() == ChessMove.Casteling.KING_SIDE) {
					b.setCellState(0, 4, null);
					b.setCellState(0, 5, ChessCellState.BLACK_ROOK);
					b.setCellState(0, 6, ChessCellState.BLACK_KING);
					b.setCellState(0, 7, null);
				} else if (chessMove.getCasteling() == ChessMove.Casteling.QUEEN_SIDE) {
					b.setCellState(0, 0, null);
					b.setCellState(0, 2, ChessCellState.BLACK_KING);
					b.setCellState(0, 3, ChessCellState.BLACK_ROOK);
					b.setCellState(0, 4, null);
				}
				b.setBlackKingSideCastleAllowed(false);
				b.setBlackQueenSideCastleAllowed(false);
			}			
		} else { //Handle non casteling
			if (b.getCellState(chessMove.fromCell).pieceColor != b.turn) {
				return null;
			}
			b.setCellState(chessMove.toCell, getCellState(chessMove.fromCell));
			b.setCellState(chessMove.fromCell, null);
			ChessCellState finalCellState = b.getCellState(chessMove.toCell);
			// If pawn moved then check if its creating or killing a passed pawn or 
			//  handle pawn promotion.
			if (finalCellState.pieceType == PieceType.PAWN) {
				if (finalCellState.pieceColor == PieceColor.BLACK) {
					if (chessMove.fromCell.getRow() == 1 && chessMove.toCell.getRow() == 3) {
						b.passedPawn = new Cell (2, chessMove.toCell.getCol());
					}
					if (passedPawn != null && chessMove.toCell.equals(passedPawn)) {
						b.setCellState(new Cell(chessMove.toCell.getRow() - 1, chessMove.toCell.getCol()), null);
					}
					if (chessMove.toCell.getRow() == 7) {
						if (chessMove.getPawnPromotion() != null) {
							b.setCellState(chessMove.toCell, new ChessCellState(chessMove.getPawnPromotion(), PieceColor.BLACK));
						}
					}
				}
				if (finalCellState.pieceColor == PieceColor.WHITE) {
					if (chessMove.fromCell.getRow() == 6 && chessMove.toCell.getRow() == 4) {
						b.passedPawn = new Cell (5, chessMove.toCell.getCol());
					}
					if (passedPawn != null && chessMove.toCell.equals(passedPawn)) {
						b.setCellState(new Cell(chessMove.toCell.getRow() + 1, chessMove.toCell.getCol()), null);
					}
					if (chessMove.toCell.getRow() == 0) {
						if (chessMove.getPawnPromotion() != null) {
							b.setCellState(chessMove.toCell, new ChessCellState(chessMove.getPawnPromotion(), PieceColor.WHITE));
						}
					}
				}
			}
			// If Rook or King moved set allowed casteling status. 
			if (finalCellState.pieceType == PieceType.ROOK) {
				if (turn == PieceColor.WHITE && chessMove.fromCell.getRow() == 7) {
					if (chessMove.fromCell.getCol() == 0) {
						b.setWhiteQueenSideCastleAllowed(false);
					}
					if (chessMove.fromCell.getCol() == 7) {
						b.setWhiteKingSideCastleAllowed(false);
					}
				}
				if (turn == PieceColor.BLACK && chessMove.fromCell.getRow() == 0) {
					if (chessMove.fromCell.getCol() == 0) {
						b.setBlackQueenSideCastleAllowed(false);
					}
					if (chessMove.fromCell.getCol() == 7) {
						b.setBlackKingSideCastleAllowed(false);
					}
				}				
			}
			if (finalCellState.pieceType == PieceType.KING) {
				if (turn == PieceColor.WHITE) {
					b.setWhiteKingSideCastleAllowed(false);
					b.setWhiteQueenSideCastleAllowed(false);
				}
				if (turn == PieceColor.BLACK) {
					b.setBlackKingSideCastleAllowed(false);
					b.setBlackQueenSideCastleAllowed(false);
				}
			}
			//Sanity check for casteling status
			if (b.getCellState(0, 0) == null || (b.getCellState(0,0).pieceType != PieceType.ROOK || b.getCellState(0,0).pieceColor != PieceColor.BLACK)) {
				b.setBlackQueenSideCastleAllowed(false);
			}
			if (b.getCellState(0, 7) == null || (b.getCellState(0,7).pieceType != PieceType.ROOK || b.getCellState(0,7).pieceColor != PieceColor.BLACK)) {
				b.setBlackKingSideCastleAllowed(false);
			}
			if (b.getCellState(7, 0) == null || (b.getCellState(7,0).pieceType != PieceType.ROOK || b.getCellState(7,0).pieceColor != PieceColor.WHITE)) {
				b.setWhiteQueenSideCastleAllowed(false);
			}
			if (b.getCellState(7, 7) == null || (b.getCellState(7,7).pieceType != PieceType.ROOK || b.getCellState(7,7).pieceColor != PieceColor.WHITE)) {
				b.setWhiteKingSideCastleAllowed(false);
			}
			if (b.getCellState(0, 4) == null || (b.getCellState(0,4).pieceType != PieceType.KING || b.getCellState(0,4).pieceColor != PieceColor.BLACK)) {
				b.setBlackQueenSideCastleAllowed(false);
				b.setBlackKingSideCastleAllowed(false);
			}
			if (b.getCellState(7, 4) == null || (b.getCellState(7,4).pieceType != PieceType.KING || b.getCellState(7,4).pieceColor != PieceColor.WHITE)) {
				b.setWhiteQueenSideCastleAllowed(false);
				b.setWhiteKingSideCastleAllowed(false);
			}
		}
		if (turn == PieceColor.WHITE) {
			b.turn = PieceColor.BLACK;
		} else {
			b.turn = PieceColor.WHITE;
		}
		return b;
	}

	@Override
	public ChessBoard cloneState (Board b) {
		ChessBoard chessBoard = (ChessBoard)b;
		super.cloneState(chessBoard);
		chessBoard.setBlackKingSideCastleAllowed(blackKingSideCastleAllowed);
		chessBoard.setBlackQueenSideCastleAllowed(blackQueenSideCastleAllowed);
		chessBoard.setWhiteKingSideCastleAllowed(whiteKingSideCastleAllowed);
		chessBoard.setWhiteQueenSideCastleAllowed(whiteQueenSideCastleAllowed);
		chessBoard.setTurn(turn);
		chessBoard.setPassedPawn(passedPawn);
		return chessBoard;
	}
	
	@Override
	public ChessBoard clone () {
		ChessBoard b = new ChessBoard(true);
		cloneState(b);
		return b;
	}	
	
	public PieceColor getTurn() {
		return turn;
	}

	public void setTurn(PieceColor turn) {
		this.turn = turn;
	}

	public boolean isBlackKingSideCastleAllowed() {
		return blackKingSideCastleAllowed;
	}

	public void setBlackKingSideCastleAllowed(boolean blackKingSideCastleAllowed) {
		this.blackKingSideCastleAllowed = blackKingSideCastleAllowed;
	}

	public boolean isBlackQueenSideCastleAllowed() {
		return blackQueenSideCastleAllowed;
	}

	public void setBlackQueenSideCastleAllowed(boolean blackQueenSideCastleAllowed) {
		this.blackQueenSideCastleAllowed = blackQueenSideCastleAllowed;
	}

	public boolean isWhiteKingSideCastleAllowed() {
		return whiteKingSideCastleAllowed;
	}

	public void setWhiteKingSideCastleAllowed(boolean whiteKingSideCastleAllowed) {
		this.whiteKingSideCastleAllowed = whiteKingSideCastleAllowed;
	}

	public boolean isWhiteQueenSideCastleAllowed() {
		return whiteQueenSideCastleAllowed;
	}

	public void setWhiteQueenSideCastleAllowed(boolean whiteQueenSideCastleAllowed) {
		this.whiteQueenSideCastleAllowed = whiteQueenSideCastleAllowed;
	}

	public Cell getPassedPawn() {
		return passedPawn;
	}

	public void setPassedPawn(Cell passedPawn) {
		this.passedPawn = passedPawn;
	}

	public AnalysisData getAnalysisData() {
		return analysisData;
	}

	public void setAnalysisData(AnalysisData analysisData) {
		this.analysisData = analysisData;
	}
	
	
}
